#pragma once

#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<ctime>
#include<cstdarg>
#include<cstring> 
#include<fstream>
#include<pthread.h>
#include"LockGuard"

enum
{
    DEBUG=1,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

std::string LevalToString(int level)
{
    switch(level)
    {
        case DEBUG:
            return "DEBUG";
        case INFO:
            return "INFO";
        case WARNING:
            return "WARNING";
        case ERROR:
            return "ERROR";
        case FATAL:
            return "FATAL";
        default:
            return "unknow";
    }
}

class logmessage
{

public:
    std::string _level;
    pid_t _pid;
    std::string _filename;
    int _filenumber;
    std::string _curr_time;
    std::string _message_info;

};

std::string GetCurrTime()
{
    time_t now=time(nullptr);
    struct tm* currtime=localtime(&now);
    char buff[128];
    snprintf(buff,sizeof(buff),"%d-%02d-%d %02d:%02d:%02d",\
    currtime->tm_year+1900,\
    currtime->tm_mon+1,\
    currtime->tm_mday,\
    currtime->tm_hour,\
    currtime->tm_min,\
    currtime->tm_sec);
    return buff;
}

#define SCREEN_TYPE 1
#define FILE_TYPE   2
pthread_mutex_t glock=PTHREAD_MUTEX_INITIALIZER;

const std::string glogfile="./log.txt";
class Log
{
public:
    Log(std::string log_file=glogfile):
    _type(SCREEN_TYPE),
    _log_file(log_file)
    {}
    void Enable(int type)//修改日志打印的地方，默认显示器
    {
        _type=type;
    }
    void FlushToScreen(const logmessage &lg)
    {
        printf("[%s][%d][%s][%d][%s]:%s",
        lg._level.c_str(),
        lg._pid,
        lg._filename.c_str(),
        lg._filenumber,
        lg._curr_time.c_str(),
        lg._message_info.c_str()
        );
    }
    void FlushToFile(const logmessage lg)
    {
        //LockGuard lock(&glock);
        std::ofstream out(_log_file,std::ios::app);
        if(!out.is_open())return;

        char buff[2048];
        snprintf(buff,sizeof(buff),"[%s][%d][%s][%d][%s]:%s",
        lg._level.c_str(),
        lg._pid,
        lg._filename.c_str(),
        lg._filenumber,
        lg._curr_time.c_str(),
        lg._message_info.c_str()
        );
        out.write(buff,strlen(buff));
        out.close();
    }
    void FlushLog(const logmessage &lg)
    {
        LockGuard lock(&glock);
        
        switch(_type)
        {
            case SCREEN_TYPE:
                FlushToScreen(lg);
                break;
            case FILE_TYPE:
                FlushToFile(lg);
                break;
            default:
                break;
        }
    }
    void LogMessage(std::string filename,int filenumber,int level,const char *format,...)//C语言式可变参数format-格式参数
    {
        logmessage lg;
        lg._level=LevalToString(level);
        lg._pid=getpid();
        lg._filename=filename;
        lg._filenumber=filenumber;
        lg._curr_time=GetCurrTime();

        va_list ap;
        va_start(ap,format);
        char log_info[1024];
        vsnprintf(log_info,sizeof(log_info),format,ap);
        va_end(ap);
        lg._message_info=log_info; 
        FlushLog(lg);
    }
    
    ~Log()
    {}
private:
    int _type;
    std::string _log_file;
};

Log lg;
#define LOG(Level,Format,...) do{lg.LogMessage(__FILE__,__LINE__,Level,Format,##__VA_ARGS__);}while(0)//宏替换自定义生成当前文件名和行数，只需要输入等级和可变参数即可
#define EnableScreen() do{lg.Enable(SCREEN_TYPE);}while(0)
#define EnableFile() do{lg.Enable(FILE_TYPE);}while(0)